<?php


namespace app\common\model;

use think\Db;
use think\Exception;
use think\Model;
use Yansongda\Pay\Pay;
use EasyWeChat\Foundation\Application;
use addons\epay\library\Service;
use addons\wechat\library\Config as ConfigService;

class Refund extends Model
{
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = true;

    // 定义时间戳字段名
    protected $createTime = 'refund_create_time';
    protected $updateTime = 'refund_update_time';



    const REFUND_STATUS        = 0;   //售后未审核
    const REFUND_STATUS_YES    = 1;   //售后审核成功
    const REFUND_STATUS_NO     = 2;   //售后审核失败
    const REFUND_STATUS_CANCEL = 3;   //取消售后
    const REFUND_THIRD_STATUS  = 4;   //第三方待审核
    const REFUND_PAY           = 0;   //待退款
    const REFUND_PAY_YES       = 1;   //退款成功
    const REFUND_PAY_NO        = 2;   //退款失败



    protected $_status = [
        'refund_status' => [
            'REFUND_STATUS',
            'REFUND_STATUS_YES',
            'REFUND_STATUS_NO',
            'REFUND_STATUS_CANCEL',
            'REFUND_THIRD_STATUS'
        ],
        'refund_pay' => [
            'REFUND_PAY',
            'REFUND_PAY_YES',
            'REFUND_PAY_NO'
        ]
    ];

    /**
     * @return string
     * 退款订单号
     */
    public function refund_no()
    {
        return time() . rand(1000, 1999);
    }

    /**
     * @return array
     * 审核状态
     */
    public function getRefundStatusList()
    {
        return ['0' => __('Status 0'),'1' => __('Status 1'),'2' => __('Status 2'),'4' => __('Status 4')];
    }

    /****
     * @return \think\model\relation\BelongsTo
     * 关联订单表
     */
    public function orders()
    {
        $field = [
            'id',
            'sell_id',
            'play_time',
            'ticket_num',
            'order_name',
            'order_phone',
            'product_name',
            'goods_id',
            'scenic_id',
            'goods_price',
            'order_amount',
            'store_id',
            'buy_role',
            'user_id'
        ];
       return $this->belongsTo('Order','order_id')
             ->field($field)->setEagerlyType(0);
    }

    /***
     * @return \think\model\relation\HasMany
     * 退款表记录
     */
    public function refundLog()
    {
        return $this->hasMany('RefundLog','refund_id')
                    ->order('type asc');
    }
    /***
     * @param array $where 查询条件
     * 售后列表
     */
    public function getAferSalesList(array $where)
    {
        $page = $where['page'];
        unset($where['page']);

        $scenicModel = new Scenic();
        $list = $this
                ->with(['orders'])
                ->where($where)
                ->order('refund_create_time desc')
                ->page($page, 10)
                ->select();
        $list = collection($list)->toArray();
        foreach ($list as &$refund){
            $refund['scenicimage'] = $scenicModel->getPicture($refund['orders']['scenic_id']);
            $refund['orders']['play_time'] = date('Y-m-d', $refund['orders']['play_time']);
            $refund['refund_create_time'] = date('Y-m-d', $refund['refund_create_time']);
            $refund['status'] = $this->getStatus($refund['refund_status'],$refund['refund_pay_status']);
            unset($refund['refund_status'],$refund['refund_pay_status']);
        }

        return $list;
    }

    /***
     * @param $order_id
     * @return array
     * 退款记录详情
     */
    public function getAfterSalesLog($order_id)
    {
        $where = [
            'order_id' => $order_id
        ];

        $order = Order::with(['goods'])->find(['id' => $order_id]);
        if ($order['goods']['refundRules']) {
            switch ($order['goods']['refundChargePlan']){
                case 0:
                    $refund_way = '无手续费';
                    break;
                case 1:
                    $refund_way = '每笔订单';
                    break;
                case 2:
                    $refund_way = '每张门票';
                    break;
                default :
                    $refund_way = '';
            }
        }else{
            $refund_way = '无手续费';
        }



        $list = $this->with(['refund_log'])
                     ->where($where)
                     ->order('refund_create_time desc')
                     ->select();
        $list = collection($list)->toArray();

        foreach ($list as &$refund){
            $refund['refund_create_time'] = date('Y-m-d H:i:s',$refund['refund_create_time']);
            if ($refund['refund_update_time']){
                $refund['refund_update_time'] = date('Y-m-d H:i:s',$refund['refund_update_time']);
            }
            foreach ($refund['refund_log'] as &$log){
                $log['ctime'] = date('Y-m-d H:i:s',$log['create_time']);
            }

            $refund['refund_way'] = $refund_way;
            $refund['status'] = $this->getStatus($refund['refund_status'],$refund['refund_pay_status']);
            unset($refund['refund_status'],$refund['refund_pay_status']);
        }
        return $list;
    }



    /***
     * @param $refund_code 状态码
     * @param $pay_code
     * @return mixed
     *退款状态标识
     */
    protected function getStatus($refund_code,$pay_code)
    {
        if ($refund_code == Refund::REFUND_STATUS){
            $status = $this->_status['refund_status'][$refund_code];
        }elseif ($refund_code == self::REFUND_STATUS_YES && $pay_code == self::REFUND_PAY){
            $status = $this->_status['refund_pay'][$pay_code];
        }elseif ($refund_code == self::REFUND_STATUS_YES && $pay_code == self::REFUND_PAY_YES){
            $status = $this->_status['refund_pay'][$pay_code];
        }elseif ($refund_code == self::REFUND_STATUS_YES && $pay_code == self::REFUND_PAY_NO){
            $status = $this->_status['refund_pay'][$pay_code];
        }elseif ($refund_code == self::REFUND_STATUS_NO){
            $status = $this->_status['refund_pay'][$refund_code];
        }elseif ($refund_code == self::REFUND_STATUS_CANCEL){
            $status = $this->_status['refund_status'][$refund_code];
        }elseif ($refund_code == self::REFUND_THIRD_STATUS) {
            $status = $this->_status['refund_status'][$refund_code];
        }

        return $status;
    }

    /***
     * @param array $params
     * @return false|int
     * @throws Exception
     * 退款申请
     */
    public function createRefund(array $params)
    {
        $refund_log = new RefundLog();
        $order = new Order();
        $order_info = $order->get(['id' =>$params['order_id']]);
        try {
            $result = $this->allowField(true)->save($params);
            $order->revokeOrder($params['order_id'],$params['refund_num']);//撤销订单
            $refund_log->refundLog($this->id, RefundLog::REFUND_TYPE_APPY, '退款申请');//退款操作日志
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
        
        return $result;
    }

    /***
     * @param $order_id
     * @return bool
     * 判断是否全退
     */
    public function isAllRefund($order_id)
    {
        $order = Order::get(['id' => $order_id]);
        if ($order['refund_mark'] == Order::REFUND_MARK_PARTIAL) {
            return false;
        } elseif ($order['refund_mark'] == Order::REFUND_MARK_YES) {
            return true;
        }

    }


    /**
     * [auditRefund 退款审核]
     * @Author   ZhouYunpeng
     * @DateTime 2020-12-30
     * @param    [type]      $refund_id [description]
     * @param    array       $params    [description]
     * @return   [type]                 [description]
     */
    public function auditRefund($refund_id,$params = [])
    {
        $refund  = $this->get(['id' => $refund_id]);
        $order   = new Order();
        $is_all  = $this->isAllRefund($refund['order_id']);
        $log     = new RefundLog();
        $result  = $refund->allowField(true)->save($params);
        if ($result == false){
            return false;
        }
        if ($params['refund_status'] == self::REFUND_STATUS_YES) {
            $status = RefundLog::REFUND_TYPE_AUDIT;
            $status_msg = '审核成功';
            $this->rebate($refund['order_id'],$refund['refund_num'],$is_all);//返利
            $this->refundPay($refund);//退款支付
           //是否绑定第三方商品
           $goods_order = Order::where(['id' => $refund['order_id']])->find();
           
          if ($goods_order['is_third']) {
              $third_goods = Db::name('thirdparty_goods')->where(['goods_id'=>$goods_order['goods_id']])->find();
              switch ($third_goods['system_id']) {
                case '1':
                  $otc =  new \app\common\model\thirdparty\Oct();
                  $result = $otc->orderRefund($refund['order_id'],$refund['refund_num']);
                  break;
                case '2':
                  $pft =  new \app\common\model\thirdparty\Pft();
                  $result = $pft->orderRefund($refund['order_id'],$refund['refund_num']);
                  break;
                case '3':
                  $zyb =  new \app\common\model\thirdparty\Zyb();
                  $result = $zyb->orderRefund($refund['order_id'],$refund['refund_num']);
                  break;
                default:
                  # code...
                  break;
              }
           }
        } elseif ($params['refund_status'] == self::REFUND_STATUS_NO) {
          
            $status = RefundLog::REFUND_TYPE_FAILED;
            $status_msg = '审核失败';
            //退款审核失败恢复订单状态
            $order->recallRefund($refund['order_id'], $refund['refund_num']);
        }
        $log->refundLog($refund_id, $status, $status_msg);

        return $result;
    }
    

    /**
     * [outAuditRefund 退款自动审核]
     * @Author   ZhouYunpeng
     * @DateTime 2020-12-30
     * @param    [type]      $refund_id [description]
     * @return   [type]                 [description]
     */
    public function outAuditRefund($refund_id)
    {
        $refund = $this->get(['id' => $refund_id]);
        $order  = Order::with(['goods'])
                ->where(['order.id' => $refund['order_id']])
                ->find();
        $is_all = $this->isAllRefund($refund['order_id']);
        $log    = new RefundLog();

        if ($order['goods']['refundCheck']) {
             //是否绑定第三方商品
              if ($order['is_third']) {
                 $third_goods = Db::name('thirdparty_goods')->where(['goods_id'=>$order['goods_id']])->find();
                  switch ($third_goods['system_id']) {
                    case '1':
                      $otc =  new \app\common\model\thirdparty\Oct();
                      $result = $otc->orderRefund($refund['order_id'],$refund['refund_num']);
                      break;
                    case '2':
                      $pft =  new \app\common\model\thirdparty\Pft();
                      $result = $pft->orderRefund($refund['order_id'],$refund['refund_num']);
                      break;
                    case '3':
                      $zyb =  new \app\common\model\thirdparty\Zyb();
                      $result = $zyb->orderRefund($refund['order_id'],$refund['refund_num']); 
                      break;
                    default:
                      # code...
                      break;
                  }

               }else{
                   $result = 1;
               }
            
             if ($result == 1) {
                //不需要人工审核
                $refund->save(['refund_status'=>self::REFUND_STATUS_YES]);
                $status = RefundLog::REFUND_TYPE_AUDIT;
                $status_msg = '审核成功';
                $log->refundLog($refund_id, $status, $status_msg);
                $this->rebate($refund['order_id'],$refund['refund_num'],$is_all);//返利   
                return true;
             }elseif ($result == 2) {
                $refund->save(['refund_status'=>self::REFUND_THIRD_STATUS]);
                return false;
             }else{
                $refund->save(['refund_status' =>self::REFUND_STATUS_NO]);
                $status = RefundLog::REFUND_TYPE_FAILED;
                $status_msg = '审核失败';
                //退款审核失败恢复订单状态
                $orders = new Order();
                $orders->recallRefund($refund['order_id'], $refund['refund_num']);
                $log->refundLog($refund_id, $status, $status_msg);
                return false;
             }

        }
    }


    /**
     * [thirdAuditRefund 第三方产品退款审核]
     * @Author   ZhouYunpeng
     * @DateTime 2020-06-10
     * @param    [type]      $refund_id [description]
     * @param    array       $params    [description]
     * @return   [type]                 [description]
     */
    public function thirdAuditRefund($refund_id,$params = [])
    {
        $refund = $this->get(['id' => $refund_id]);
        if ($params['refund_status'] == 1) {
            $params['refund_status'] = 4;
        }

        if ($params['refund_status'] == 4) {
              //是否绑定第三方商品
             $goods_order = Order::where(['id' => $refund['order_id']])->find();
             $third_goods = Db::name('thirdparty_goods')->where(['goods_id'=>$goods_order['goods_id']])->find();
            if ($third_goods) { 
                switch ($third_goods['system_id']) {
                  case '1':
                    $otc =  new \app\common\model\thirdparty\Oct();
                    $result = $otc->orderRefund($refund['order_id'],$refund['refund_num']);
                    break;
                  case '2':
                    $pft =  new \app\common\model\thirdparty\Pft();
                    $result = $pft->orderRefund($refund['order_id'],$refund['refund_num']);
                    break;
                  case '3':
                    $zyb =  new \app\common\model\thirdparty\Zyb();
                    $result = $zyb->orderRefund($refund['order_id'],$refund['refund_num']);  
                    break;
                  default:
                    # code...
                    break;
                }
            }else{
                return ['code'=>201,'msg'=>'产品未对接第三方'];
            }
            if ($result == 2) {
               $result = $refund->allowField(true)->save($params);
               return ['code'=>200,'msg'=>'退票申请成功，第三方待审核'];
             }elseif ($result == 1) {
                $refund->where(['id' => $refund_id])->update(['refund_status'=> self::REFUND_STATUS_YES]);
                $status = RefundLog::REFUND_TYPE_AUDIT;
                $log = new RefundLog();
                $log->refundLog($refund_id, $status, '审核成功');
                $is_all = $this->isAllRefund($refund['order_id']);
                $this->rebate($refund['order_id'],$refund['refund_num'],$is_all);//返利  
                $this->refundPay($refund);//退款支付 
                $params['refund_status'] = 1;
                $result = $refund->allowField(true)->save($params);
                return ['code'=>200,'msg'=>'第三方提交审核成功'];
             }else{
                return ['code'=>201,'msg'=>'第三方提交审核失败'];
             }

  
        }elseif ($params['refund_status'] == self::REFUND_STATUS_NO) {
            $log = new RefundLog();
            $order = new Order();
            $status = RefundLog::REFUND_TYPE_FAILED;
            $status_msg = '审核失败';
            //退款审核失败恢复订单状态
            $order->recallRefund($refund['order_id'], $refund['refund_num']);
            $log->refundLog($refund_id, $status, $status_msg);
            $refund->allowField(true)->save($params);
            return ['code'=>200,'msg'=>'审核成功'];
        }

    }

    /**
     * [noTicketRefund 第三方未出票退款(手动)]
     * @Author   ZhouYunpeng
     * @DateTime 2020-07-17
     * @return   [type]      [description]
     */
    public function noTicketRefund($refund_id)
    {

        $refund = $this->get(['id' => $refund_id]);
        $refund->where(['id' => $refund_id])->update(['refund_status'=>self::REFUND_STATUS_YES]);
        $log = new RefundLog();
        $is_all = 1;
        $status = RefundLog::REFUND_TYPE_AUDIT;
        $status_msg = '审核成功';
        $log->refundLog($refund_id, $status, $status_msg);
        $this->rebate($refund['order_id'],$refund['refund_num'],$is_all);//返利  
        return true;
    }

    
    /**
     * [automaticRefund 第三方未出票自动退款]
     * @Author   ZhouYunpeng
     * @DateTime 2021-10-21
     * @param    [type]      [description]
     */
    public function automaticRefund($row)
    {
        $data = [
            'order_id'             => $row->id,
            'buy_role'             => $row->buy_role,
            'user_id'              => $row->user_id,
            'goods_id'             => $row->goods_id,
            'store_id'             => $row->store_id,
            'refund_num'           => $row->ticket_num,
            'refund_amount'        => $row->order_amount,
            'refund_charge'        => 0,
            'out_refund_no'        => $this->refund_no(), 
            'out_trade_no'         => $row->out_trade_no,
            'pay_trade_no'         => $row->pay_trade_no,
            'refund_reason'        => '出票失败',
            'leave_message'        => '',
            'refund_actual_amount' => $row->order_amount,
            'refund_pay_type'      => $row->pay_type,
            'refund_status'        => 1,
            'refund_pay_status'    => 1,
            'is_third'             => $row->is_third
        ];
          
        $this->createRefund($data);
        $data['id'] = $this->id;
        $this->refundPay($data);
        $refundLogModel = new RefundLog();
        $refundLogModel->refundLog($data['id'],4,'退款支付成功');

        $orderLogModel = new OrderLog();    
        $orderLogModel->createLog($row['id'], 4, '订单取消'); 
        
        //恢复库存
        // $orderModel = new \app\common\model\Order();  
        // $orderModel->subtractTotalSales($row['goods_id'],$row['ticket_num'],$row['play_time']);

    }

    /**
     * @param $order_id
     * @param $number
     * @param bool $is_all
     * 退款成功后更改返利
     */
    public function rebate($order_id,$number,$is_all = true)
    {
            try{
                if ($is_all){
                    //全部退
                    Rebate::deleteRebate($order_id);
                }else{
                    //部分退
                    Rebate::updateRebate($order_id,$number);
                }
            }catch (Exception $e){
                \exception($e->getMessage());
            }

    }

    /**
     * [cancelRefund 取消退款]
     * @Author   ZhouYunpeng
     * @DateTime 2020-04-03
     * @return   [type]      [description]
     */
    public function cancelRefund($id)
    {
        $refund_log = new RefundLog();
        $order = new Order();
        Db::startTrans();
        try{
            $wehre = [
                'id' => $id,
                'refund_status' => ['neq', self::REFUND_STATUS_YES]
            ];
            $refund = $this
                ->where($wehre)
                ->find();
            if (!$refund) {
                return false;
            }
            $order->recallRefund($refund->order_id,$refund->refund_num);//恢复订单状态
            //更新退款表状态
            $refund->save(['refund_status' => self::REFUND_STATUS_CANCEL]);

            $refund_log->refundLog($id, RefundLog::REFUND_TYPE_CANCEL, '用户取消退款');//退款操作日志
            Db::commit();
        }catch (Exception $e){
            Db::rollback();
            throw new Exception($e->getMessage());
        }
    }


    /**
     * [refund_pay 退款支付]
     * @Author   ZhouYunpeng
     * @DateTime 2020-04-11
     * @param    [type]      $id  [description]
     * @return   [type]           [description]
     */
    public function refundPay($refund)
    {
        // $refund = Refund::get(['id'=>$refund_id]);
        $order  = \app\common\model\Order::get(['id' => $refund['order_id']]);
        if ($order['pay_type'] == 'alipay') {
            //支付宝退款
            $config = Service::getConfig('alipay');
            $alipay = Pay::alipay($config);
            $data = [
                   'trade_no'  => $order->pay_trade_no,          //支付宝交易号
                   'out_request_no' =>time(),                    //标识一次退款请求
                   // 'refund_amount' => 0.01,                   //退款金额
                   'refund_amount' => $refund['refund_amount']-$refund['refund_charge'],  //退款金额
            ];

            $result = $alipay->refund($data);
           if ($result['code']== '10000' && $result['msg'] == 'Success' && $result['fund_change'] == 'Y') {
                $refund_status  =  1;
            }else{
                $refund_status  =  0;
            }
        }elseif ($order['pay_type'] == 'wechatpay') {
            //微信退款
            //创建支付对象
            $config = Service::getConfig('wechat');
            $pay    = Pay::wechat($config);
            $data = [
                   'transaction_id'  => $order->pay_trade_no,          //商户订单号
                   'out_refund_no'   => time(),                        //商户退款单号
                   'total_fee'       => $order['order_amount'] *100,   //订单金额
                   'refund_fee'      => ($refund['refund_amount']*100)-($refund['refund_charge']*100),//退款金额
                   // 'total_fee'       => 1,   //测试订单金额
                   // 'refund_fee'      => 1,  //测试退款金额
            ];
            switch ($order['pay_method']) {
                  case 'mp':
                      //公众号支付退款
                      $result = $pay->refund($data);
                      break;
                  case 'wap':
                      //手机网页支付退款
                      $result = $pay->refund($data);
                      break;
                  case 'app':
                      //APP退款
                      $data['type'] = 'app';
                      $result = $pay->refund($data);
                      break;
                  case 'miniapp':
                      //小程序退款
                      $data['type'] = 'miniapp';
                      $result = $pay->refund($data);
                      break;
                  default:
              }

            
           if ($result['return_code'] == 'SUCCESS' && $result['return_msg'] == 'OK' && $result['result_code'] == 'SUCCESS') {
              $refund_status  =  1;
               //公众号推送退款通知
                    $user = User::get($order['user_id']);
                    if ($user['openid']) {
                         $app = new Application(ConfigService::load());   
                          //发送模板消息
                         $app->notice->send([
                                              'touser' => $user['openid'],
                                              'template_id' => 'V0D1zTFyf471_vk8W97b1YFd4FgQKwlcT8a5GDV9OZs',
                                              'url' => 'http://www.store.liuyiqinzi.com/orderinfo/'.$order['id'].'/2',
                                              'miniprogram'=>['appid'=>'wxab379d255ecd6df9',
                                                              'pagepath'=>'pages/order/OrderInfo?orderId='.$order['id'].'&orderType=4'
                                                             ],
                                              'data' => [
                                                  'first' => ['亲爱的，订单取消申请已通过。','#52627C'],
                                                  'keyword1' => [$order['product_name'],'#DB9728'],
                                                  'keyword2' => [$order['order_name'],'#52627C'],
                                                  'keyword3' => ['用户主动取消','#52627C'],
                                                  'keyword4' => [$refund['refund_amount'].'元','#FF3030'],
                                                  'keyword5' => [$order['id'],'#52627C'],
                                                  'remark' => ['退款金额将原路返还您的支付账户中，请注意查收。如有疑问请致电易行旅行客服：0531-85333222。','#52627C'],
                                              ],
                                          ]);
                    }

           }else{
              $refund_status  =  0;
           }

        }elseif ($order['pay_type'] == 'balance') {
                //余额退款
               $distributor  = User::get($order->user_id);
               $result = $distributor->money($refund['refund_amount']-$refund['refund_charge'],$distributor['id'],$type = 2 ,'商品退款',$order->id,2,$refund['refund_num']);
                if ($result) {
                    $refund_status  =  1;
                }else{
                    $refund_status  =  0;  
                }

        }elseif ($order['pay_type'] == 'wallet') {
                $user = Db::name('user')->field('money')->find($order->user_id);
                $data =[
                       'order_id' =>$order->id,
                       'user_id' =>$order->user_id,
                       'type'    =>3,
                       'money'   => $refund['refund_amount']-$refund['refund_charge'],
                       'before'  => $user['money'],
                       'after'   => $user['money']+($refund['refund_amount']-$refund['refund_charge']),
                       'createtime' => time()
                ];
                Db::name('user_money_log')->insert($data);
                $result = Db::name('user')->where('id',$order->user_id)->setInc('money',$refund['refund_amount']-$refund['refund_charge']);
                if ($result) {
                    $refund_status  =  1;
                }else{
                    $refund_status  =  0;  
                }

        }else{
            $this->error('支付方式错误！');
        }

        if ($refund_status == 1) {
            $refundLog =  new  RefundLog();
            if ($order->refund_mark == 2){
                //全部退款
                $order->pay_status = 3;
            }elseif($order->refund_mark == 1){
                //部分退款
                $order->pay_status = 2;
            }
            $order->save();
            Db::name('refund')->where(['id'=>$refund['id']])->update(['refund_pay_status'=>1]);

            $refundLog->refundLog($refund['id'],RefundLog::REFUND_TYPE_PAY,'退款完成');
            $order->subtractTotalSales($order['goods_id'],$refund['refund_num'],$order['play_time']);//恢复库存
        }else{
            $this->error('退款失败！');
        }
    }    


}